//oddeven.c 使用方法：./run.sh 程序名 进程数 数据文件名 如./run.sh oddeven 8 256Mdata
#include <mpi.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
size_t BLOCK;
float *readdata;
float *redata;
float *ndata;

int comp(const void *a, const void* b)//qsort,由小到大排序
{
    float*_a = (float*)a;
	float*_b = (float*)b;
	if (*_a > *_b) {
		return -1;
	}
	else if (*_a < *_b) {
		return 1;
	}
	else {
		return 0;
	}

}

void merge(float *a,float *b,float *c,int isBig){//进程之间归并
        int i,j,k;
        if(isBig)//从大到小
        {
                i=j=k=BLOCK-1;
                for(k=BLOCK-1;k>=0;k--)
                {
                        if(a[i]>=b[j])
                        {
                                c[k]=a[i--];
                        }
                        else
                        {
                                c[k]=b[j--];
                        }
                }
        }
        else//从小到大
        {
                i=j=0;
                for(k=0;k<BLOCK;k++)
                {
                        if(a[i]<=b[j])
                        {
                                c[k]=a[i++];
                        }
                        else
                        {
                                c[k]=b[j++];
                        }
                }
        }
        
        
        size_t bf=sizeof(float)*BLOCK;
        //total of data size(bytes)     
        memcpy(a,c,bf);//c复制到a
}


int main(int argc, char *argv[])
{
        int np,rank,oddt,event,i;//np:进程数，rank:进程序号
        float* ans;
        float t1,t2;
        char  a[10];
        FILE* fp;
        MPI_Status status;
        MPI_Init(&argc,&argv);
        MPI_Comm_size(MPI_COMM_WORLD,&np);
        MPI_Comm_rank(MPI_COMM_WORLD,&rank);
	

       
        //读取数据     
        char *filename = argv[1];
        char rankfile[30]; //copy
	    strcpy(rankfile,argv[1]);
	    sprintf(a,"%d",np);       
        strcat(filename,a);
        sprintf(a,"%d",rank);
        strcat(filename,a);
        printf("rank%d:the file name is:%s \n",rank,filename);
		
        //获取文件大小
        struct stat statbuf;
        stat(filename,&statbuf);
        long long int filesize=statbuf.st_size;
        printf("file length=%lld\n",filesize);

        //块大小 
        BLOCK=filesize/sizeof(float);
	    printf("BLOCK:%lld\n",BLOCK);
  
        readdata=(float *)malloc(filesize);
        redata=(float *)malloc(filesize);
        ndata=(float *)malloc(filesize);

        //int count = filesize/sizeof(float);
     
        
	    //get the rank's file
      
		fp=fopen(filename,"r");
		if(fp==NULL)
		{
			printf("Cannot open file \n");
			return -1; 
		}  

		fread(readdata,sizeof(float),BLOCK,fp);
		fclose(fp);
        t1=MPI_Wtime();
        qsort(readdata,BLOCK,sizeof(float),comp);//初始进程排序  
       
        if(rank%2==0)//计算交换进程
        {
                event=rank+1;
                oddt=rank-1;
        }
        else
        {
                event=rank-1;
                oddt=rank+1;
        }
        if(event==-1 || event==np) event=MPI_PROC_NULL;
        if(oddt==-1 || oddt ==np) oddt=MPI_PROC_NULL;
        for(i=0;i<np-1;i++)
        {
                if(i%2==0)//偶数次
                {
                        if(event!=MPI_PROC_NULL)
                        {
                                MPI_Sendrecv(readdata,BLOCK,MPI_FLOAT,event,0,redata,BLOCK,MPI_FLOAT,event,0,MPI_COMM_WORLD,&status);
                                printf("rankID= %d send and receive\n",rank);
                                merge(readdata,redata,ndata,event<rank);
				
                                 
                        }
                }
                else//奇数次
                {
                        if(oddt!=MPI_PROC_NULL)
                        {
                                MPI_Sendrecv(readdata,BLOCK,MPI_FLOAT,oddt,1,redata,BLOCK,MPI_FLOAT,oddt,1,MPI_COMM_WORLD,&status);
                                printf("rankID= %d send and receive\n",rank);
                                merge(readdata,redata,ndata,oddt<rank);
				        }
                }
        }
        t2=MPI_Wtime();
        free(redata);
        free(ndata);
       //信息传递
        long long int fsnp =filesize*np;
        printf("fsnp:%lld\n",fsnp);
        ans =(float *)malloc(fsnp);
        if(ans!=NULL)
        {
                printf("malloc is OK!\n");
        }
        else
        {
                printf("malloc is NULL!\n");
        }
        MPI_Gather(readdata,BLOCK,MPI_FLOAT,ans,BLOCK,MPI_FLOAT,0,MPI_COMM_WORLD);
        t2=MPI_Wtime();
        printf("my rank is %d and time is %f \n",rank,t2-t1);
        MPI_Finalize();
        free(ans);
        return 0;
}
